package org.akomantoso.core.data;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.akomantoso.core.io.Externalizable;
import org.akomantoso.core.io.Input;
import org.akomantoso.core.io.Output;
import org.akomantoso.core.visitor.AKVisitable;
import org.akomantoso.core.visitor.AKVisitor;

/**
 * <pre>
 * <xsd:element name="meta">
 *   <xsd:complexType>
 * 		<xsd:sequence>
 * 			<xsd:element ref="identification"/>
 * 			<xsd:element ref="publication" minOccurs="0" maxOccurs="1"/>
 * 			<xsd:element ref="classification" minOccurs="0" maxOccurs="unbounded"/>
 * 			<xsd:element ref="lifecycle" minOccurs="0" maxOccurs="unbounded"/>
 * 			<xsd:element ref="workflow" minOccurs="0" maxOccurs="unbounded"/>
 * 			<xsd:element ref="analysis" minOccurs="0" maxOccurs="unbounded"/>
 * 			<xsd:element ref="temporalData" minOccurs="0" maxOccurs="unbounded"/>
 * 			<xsd:element ref="references" minOccurs="0" maxOccurs="unbounded"/>
 * 			<xsd:element ref="notes" minOccurs="0" maxOccurs="unbounded"/>
 * 			<xsd:element ref="proprietary" minOccurs="0" maxOccurs="unbounded"/>
 * 			<xsd:element ref="presentation" minOccurs="0" maxOccurs="unbounded"/>
 * 		</xsd:sequence>
 * 	  </xsd:complexType>
 * </xsd:element>
 * </pre>
 * 
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 * 
 * @since http://www.akomantoso.org/1.0
 */
// TODO ....
public final class Meta implements Externalizable, AKVisitable {

	public static final String ELEMENT = "meta";

	// mandatory
	private final Identification _identification = new Identification();

	private Publication _publication;
	private List<Classification> _classifications;
	private List<Lifecycle> _lifecycles;
	private List<Workflow> _workflows;
	private List<Analysis> _analysis;
	private List<TemporalData> _temporalData;
	private List<References> _references;
	private List<Notes> _notes;
	private List<Proprietary> _proprietaries;
	private List<Presentation> _presentations;

	public Identification getIdentification() {
		return _identification;
	}

	public Publication getPublication() {
		return _publication;
	}

	public void setPublication(Publication publication) {
		_publication = publication;
	}

	public List<Lifecycle> getLifecycles() {
		return _lifecycles;
	}

	public void setLifecycles(List<Lifecycle> lifecycles) {
		_lifecycles = lifecycles;
	}

	public void addLifecyle(Lifecycle lifecycle) {
		if (_lifecycles == null) {
			_lifecycles = new ArrayList<Lifecycle>();
		}
		_lifecycles.add(lifecycle);
	}

	public List<TemporalData> getTemporalData() {
		return _temporalData;
	}

	public void setTemporalData(List<TemporalData> temporalData) {
		_temporalData = temporalData;
	}

	public void addTemporalData(TemporalData temporalData) {
		if (_temporalData == null) {
			_temporalData = new ArrayList<TemporalData>();
		}
		_temporalData.add(temporalData);
	}

	public List<References> getReferences() {
		return _references;
	}

	public void setReferences(List<References> references) {
		_references = references;
	}

	public void addReferences(References references) {
		if (_references == null) {
			_references = new ArrayList<References>();
		}
		_references.add(references);
	}

	public List<Proprietary> getProprietaries() {
		return _proprietaries;
	}

	public void setProprietaries(List<Proprietary> proprietaries) {
		_proprietaries = proprietaries;
	}

	public void addProprietary(Proprietary proprietary) {
		if (_proprietaries == null) {
			_proprietaries = new ArrayList<Proprietary>();
		}
		_proprietaries.add(proprietary);
	}

	public List<Analysis> getAnalysis() {
		return _analysis;
	}

	public void setAnalysis(List<Analysis> analysis) {
		_analysis = analysis;
	}

	public List<Workflow> getWorkflows() {
		return _workflows;
	}

	public void setWorkflows(List<Workflow> workflows) {
		_workflows = workflows;
	}

	public List<Notes> getNotes() {
		return _notes;
	}

	public void setNotes(List<Notes> notes) {
		_notes = notes;
	}

	/**
	 * @see org.akomantoso.core.io.Externalizable#writeExternal(org.akomantoso.core.io.Output)
	 */
	public <T extends Output> void writeExternal(T out) throws IOException {
		out.writeStart(ELEMENT);
		_identification.writeExternal(out);
		
		if (_publication != null) {
			_publication.writeExternal(out);
		}
		
		if (_classifications != null) {
			for (int i = 0, n = _classifications.size(); i < n; i++) {
				_classifications.get(i).writeExternal(out);
			}
		}
		
		if (_lifecycles != null) {
			for (int i = 0, n = _lifecycles.size(); i < n; i++) {
				_lifecycles.get(i).writeExternal(out);
			}
		}
		
		if (_workflows != null) {
			for (int i = 0, n = _workflows.size(); i < n; i++) {
				_workflows.get(i).writeExternal(out);
			}
		}
		
		if (_analysis != null) {
			for (int i = 0, n = _analysis.size(); i < n; i++) {
				_analysis.get(i).writeExternal(out);
			}
		}

		if (_temporalData != null) {
			for (int i = 0, n = _temporalData.size(); i < n; i++) {
				_temporalData.get(i).writeExternal(out);
			}
		}
		
		if (_references != null) {
			for (int i = 0, n = _references.size(); i < n; i++) {
				_references.get(i).writeExternal(out);
			}
		}
		
		if (_notes != null) {
			for (int i = 0, n = _notes.size(); i < n; i++) {
				_notes.get(i).writeExternal(out);
			}
		}
		
		if (_proprietaries != null) {
			for (int i = 0, n = _proprietaries.size(); i < n; i++) {
				_proprietaries.get(i).writeExternal(out);
			}
		}

		if (_presentations != null) {
			for (int i = 0, n = _presentations.size(); i < n; i++) {
				_presentations.get(i).writeExternal(out);
			}
		}
		
		out.writeEnd();
	}

	/**
	 * @see org.akomantoso.core.io.Externalizable#readExternal(org.akomantoso.core.io.Input)
	 */
	public <T extends Input> void readExternal(T in) throws IOException {

		in.readNextStartElement();

		_identification.readExternal(in);

		if (Publication.ELEMENT == in.getLocalName()) {
			_publication = new Publication();
			_publication.readExternal(in);
			in.readNextStartElement();
		}

		if (Classification.ELEMENT == in.getLocalName()) {
			Classification classification;
			_classifications = new ArrayList<Classification>(4);
			while (Classification.ELEMENT ==  in.getLocalName()) {
				_classifications.add(classification=new Classification());
				classification.readExternal(in);
			}
		}

		if (Lifecycle.ELEMENT == in.getLocalName()) {
			Lifecycle lifecycle;
			_lifecycles = new ArrayList<Lifecycle>(4);
			while (Lifecycle.ELEMENT == in.getLocalName()) {
				_lifecycles.add(lifecycle=new Lifecycle());
				lifecycle.readExternal(in);
			}
		}

		if (Workflow.ELEMENT == in.getLocalName()) {
			Workflow workflow;
			_workflows = new ArrayList<Workflow>(4);
			while (Workflow.ELEMENT == in.getLocalName()) {
				_workflows.add(workflow = new Workflow());
				workflow.readExternal(in);
				in.readNextStartElement();
			}
		}

		if (Analysis.ELEMENT == in.getLocalName()) {
			_analysis = new ArrayList<Analysis>(4);
			while (Analysis.ELEMENT == in.getLocalName()) {
				_analysis.add(new Analysis());
				_analysis.get(_analysis.size() - 1).readExternal(in);
				in.readNextStartElement();
			}
		}
		
		if (TemporalData.ELEMENT == in.getLocalName()) {
			_temporalData = new ArrayList<TemporalData>(4);
			TemporalData temporalData;
			while (TemporalData.ELEMENT == in.getLocalName()) {
				_temporalData.add(temporalData = new TemporalData());
				temporalData.readExternal(in);
				in.readNextStartElement();
			}
		}

		if (References.ELEMENT == in.getLocalName()) {
			_references = new ArrayList<References>(4);
			References references;
			while (References.ELEMENT == in.getLocalName()) {
				_references.add(references = new References());
				references.readExternal(in);
				in.readNextStartElement();
			}
		}

		if (Notes.ELEMENT == in.getLocalName()) {
			Notes notes;
			_notes = new ArrayList<Notes>(4);
			while (Notes.ELEMENT == in.getLocalName()) {
				_notes.add(notes = new Notes());
				notes.readExternal(in);
				in.readNextStartElement();
			}
		}
		
		if (Proprietary.ELEMENT == in.getLocalName()) {
			_proprietaries = new ArrayList<Proprietary>(4);
			Proprietary proprietary;
			while (Proprietary.ELEMENT == in.getLocalName()) {
				_proprietaries.add(proprietary =  new Proprietary());
				proprietary.readExternal(in);
				in.readNextStartElement();
			}
		}
		
		if (Presentation.ELEMENT == in.getLocalName()) {
			_presentations = new ArrayList<Presentation>(4);
			Presentation presentation;
			while (Presentation.ELEMENT == in.getLocalName()) {
				_presentations.add(presentation =  new Presentation());
				presentation.readExternal(in);
				in.readNextStartElement();
			}
		}
	}

	/**
	 * @see org.akomantoso.core.visitor.AKVisitable#accept(org.akomantoso.core.visitor.AKVisitor)
	 */
	@Override
	public void accept(AKVisitor visitor) {
		if (visitor.visitBegin(this)) {
			// TODO
			visitor.visitEnd(this);
		}
	}

}